﻿namespace Chunker.Inpe {
    using System;
    using System.Threading;
    using System.IO;
    using System.Linq;
    using Chunker.Inpe.Data;
    using Chunker.Inpe.Data.SqlServer;

    /// <summary>
    /// Chunk INPE images.
    /// </summary>
    public class InpeChunker {
        /// <summary>
        /// Configuration to use for all files.
        /// </summary>
        private static Configuration configuration;

        private static int _size;
        private static int _done;

        /// <summary>
        /// Chunks all files in a given path.
        /// </summary>
        /// <param name="inputpath"></param>
        public static void ChunkFiles(string source) {
            string[] files = Directory.GetFiles(source, "*.png", SearchOption.TopDirectoryOnly);
            int windowSize = 16;
            using (var entities = new InpeEntitiesSqlServer()) {
                configuration = entities.Configuration.FirstOrDefault(x => x.WindowSize == windowSize &&
                                                                           x.Source.Equals(source));
                if (configuration == null) {
                    configuration = new Configuration();
                    configuration.DHash = Convert.ToInt32(ChunkController.DHASH);
                    configuration.MaxSize = ChunkController.MAX_CHUNK_SIZE;
                    configuration.MinSize = ChunkController.MIN_CHUNK_SIZE;
                    configuration.WindowSize = windowSize;
                    configuration.Source = source;
                    entities.AddToConfiguration(configuration);
                    entities.SaveChanges();
                }

                _size = files.Length;
                _done = 0;
                foreach (string file in files) {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(ChunkFile), file);
                }

                // Wait 'till the first configuration...
                while (_done < _size) ;
            }
        }

        /// <summary>
        /// To be called from a thread.
        /// </summary>
        /// <param name="arg"></param>
        private static void ChunkFile(object arg) {
            string filepath = arg as string;

            string filename = new FileInfo(filepath).Name;
            if (ImageController.FileCompleted(filename, configuration.IdConfiguration)) {
                _done++;
                return;
            }

            Console.WriteLine("Chunking file {0}...", filename);

            int imageId = ImageController.SaveImage(filepath, configuration.IdConfiguration);
            ChunkController chunker = new ChunkController();
            chunker.ChunkCreated += (sender, e) => { ImageChunkController.SaveChunk(e.Chunk, imageId); };
            chunker.ChunkFile<Chunk>(filepath, configuration.WindowSize, configuration.MinSize, configuration.MaxSize, (ulong)configuration.DHash);
            ImageController.SetCompleted(filename, configuration.IdConfiguration);

            Console.WriteLine("{0} to go.", (_size - _done));
            _done++;
        }
    }
}
